import { _decorator, Component, js } from "cc";
import { UIPackage } from "fairygui-cc";
import { FuiCom } from "../../ui_gen/FuiCom";
import { Defer } from "../Utils/Defer";
import { BaseFacade } from "./BaseFacade";
import { GameMediator } from "./GameMediator";
import { Ctor, RegistPMVC, RFCtrl } from "./RegistFunc";
import { GameFacade } from "./GameFacade";

const { ccclass, property } = _decorator;

@ccclass('BaseCtrl')
export class BaseCtrl extends Component {
    protected onLoad(): void {
        RegistPMVC.bindView(Object.getPrototypeOf(this).constructor, this);
    }
}
export class UICtrl<T> {
    com: T;
    comCtor: Ctor<T>;
    facade: Ctor<BaseFacade>;
    mediator: GameMediator;
    bind(com: T) {
        this.com = com;
    }
    isLoaded: boolean = false;
    constructor(ctor: Ctor<T>, facade: Ctor<BaseFacade>, mediator: GameMediator) {
        this.facade = facade;
        this.mediator = mediator;
        this.comCtor = ctor;
    }
    show() {

    }
    hide() {

    }
    load() {

    }
    clear() {

    }
}

export class CCCtrl<T extends Component> extends UICtrl<T> {
    show() {
        this.com.node.active = true;
    }
    hide() {
        this.com.node.active = false;
    }
}
export class FuiCtrl<T extends FuiCom> extends UICtrl<T> {
    private static loadedPkg: Map<string, UIPackage> = new Map();
    private static comInfoMap: Map<Ctor<any>, { pkgName: string, comName: string }> = new Map();

    private static ctrlMap: Map<Ctor<any>, FuiCtrl<any>> = new Map();

    private fuiInput: Fui<T>;
    public static registFInput<T extends FuiCom>(ctor: Ctor<T>, fui: Fui<T>) {
        let func = () => {
            if (this.ctrlMap.has(ctor)) {
                this.ctrlMap.get(ctor).fuiInput = fui;
            }
            else {
                console.error("fui未注册ctrl:", ctor.name);
            }

        }
        RegistPMVC.registFunc(7, func);
    }
    public static registFui<T extends FuiCom>(ctor: Ctor<T>, pkgName: string, comName: string) {
        RFCtrl(GameFacade)(ctor);
        let func = () => {
            let ctrl = RegistPMVC.viewComMap.get(ctor) as FuiCtrl<T>;
            this.ctrlMap.set(ctor, ctrl);
        }
        this.comInfoMap.set(ctor, { pkgName, comName });
        RegistPMVC.registFunc(6, func);
    }
    static async loadFuiPkg(pkgName: string) {
        if (this.loadedPkg.has(pkgName)) return;
        js.getClassByName(pkgName + "Binder")['bindAll']?.();
        let defer = new Defer();
        UIPackage.loadPackage("fui/" + pkgName, (err, pkg) => {
            if (err) {
                console.error(err);
                defer.reject();
            }
            else {
                this.loadedPkg.set(pkgName, pkg);
                defer.resolve();
            }
        })
        await defer.promise;
    }
    static unLoadFuiPkg(pkgName: string) {
        this.loadedPkg.delete(pkgName);
    }
    static isLoadPkg(pkgName: string) {
        return this.loadedPkg.has(pkgName);
    }
    async show(): Promise<void> {
        if (!this.isLoaded) {
            await this.load();
        }
        this.com.visible = true;
        this.fuiInput.onShow();
    }
    hide(): void {
        this.com.visible = false;
        this.fuiInput.onHide();
    }
    async load() {
        if (this.isLoaded) {
            return;
        }
        let { pkgName, comName } = FuiCtrl.comInfoMap.get(this.comCtor);
        if (!FuiCtrl.loadedPkg.has(pkgName)) {
            await FuiCtrl.loadFuiPkg(pkgName);
        }
        let com = UIPackage.createObject(pkgName, comName) as T;
        this.com = com;
        this.com.onCreate();
        this.hide();
        this.fuiInput.com = com;
        this.fuiInput.onLoad();
        this.isLoaded = true;
    }
    clear(): void {
        this.fuiInput.onClear();
        this.fuiInput.com = null;
        this.com.onClear();
        this.com = null;
        this.isLoaded = false;
    }
}
export function RFInput<T extends FuiCom, K extends Fui<T>>(com: Ctor<T>) {
    return function (ctor: Ctor<K>) {
        FuiCtrl.registFInput(com, new ctor());
    }
}
/**此类只处理UI视图的输入（如点击，拖动等） */
export class Fui<T extends FuiCom> {
    com: T;
    onLoad() {

    }
    onShow() {

    }
    onHide() {

    }
    onClear() {

    }
}